﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Defect_Tracking_System.Models;
using Defect_Tracking_System.Helpers;

namespace Defect_Tracking_System.Controllers
{
    public class ProjectController : Controller
    {
        //
        // GET: /Project/
        ProjectManagement Pm = ProjectManagement.GetInstance();
        AccountManagement Am = AccountManagement.GetInstance();
        DefectManagement Dm = DefectManagement.GetInstance();

        [Authorize]
        public ActionResult Index(int PageIndex = 1)
        {
            Pm.TriggerDeleteProject();
            Account LoginedAccount = Am.GetUserByUserName(User.Identity.Name);

            if (LoginedAccount.Role == "User")
            {
                ViewData["EditRight"] = false;
            }
            else
            {
                ViewData["EditRight"] = true;
            }

            PaginatedList<Project> Model = new PaginatedList<Project>(Pm.GetProjects(LoginedAccount.UserName), PageIndex, 10);
            if (PageIndex < 1 || PageIndex > Model.TotalPages)
            {
                ViewData["message"] = "Link is invalid, please try again";
                return View("Error");
            }
            ViewData["TempDelete"] = Pm.GetDeleteProjects();
            return View(Model);
        }
        
        [Authorize(Roles="Group Admin,Project Admin")]
        public ActionResult AddProject()
        {
            return View();
        }
       
        [Authorize(Roles="Group Admin,Project Admin"),HttpPost]
        public ActionResult AddProject(ProjectModel Model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    Model.UserName = User.Identity.Name;
                    Pm.AddProject(Model);
                    ViewData["message"] = "Create project successfully.";
                }
                catch (Exception Ex)
                {
                    ViewData["message"] = Ex.Message;
                }             
            }
            return View(Model);
        }

        [HttpGet]
        [Authorize(Roles = "Group Admin,Project Admin")]
        public ActionResult EditProject(string ProjectId)
        {
            Guid G;
            if (!Guid.TryParse(ProjectId, out G))
            {
                ViewData["message"] = "Project Id is invalid";
                return View("Error");
            }
            ProjectModel Model = Pm.GetProjectModel(ProjectId);
            ViewData["ProjectId"] = ProjectId;
            return View(Model);
        }

        [HttpPost]
        [Authorize(Roles = "Group Admin,Project Admin")]
        public ActionResult EditProject(string ProjectId, ProjectModel Model)
        {
            bool IsTemp = false;
            List<TempLockProject> Li = Pm.GetDeleteProjects();
            foreach (TempLockProject Tp in Li)
            {
                if (Tp.ProjectId == ProjectId)
                {
                    IsTemp = true;
                }
            }

            if (IsTemp)
            {
                ViewData["message"] = "Sorry, you can't edit this project !";
                return View("Error");
            }
              
            if (ModelState.IsValid)
            {
                try
                {
                    Pm.EditProject(ProjectId, Model);
                }
                catch (Exception Ex)
                {
                    ViewData["message"] = Ex.Message;
                    return View("Error");
                }
                ViewData["message"] = "Edit project successfully";
            }
            ViewData["ProjectId"] = ProjectId;
            return View(Model);
        }

        [Authorize(Roles = "Group Admin,Project Admin")]
        public ActionResult DeleteProject(string ProjectId)
        {
            try
            {
                Pm.LockProject(ProjectId);
            }
            catch (Exception Ex)
            {
                ViewData["message"] = Ex.Message;
                return View("Error");
            }
            return RedirectToAction("Index");
        }

        [Authorize(Roles = "Group Admin,Project Admin")]
        public ActionResult RestoreProject(string ProjectId)
        {
            try
            {
                Pm.UnlockProject(ProjectId);
            }
            catch (Exception Ex)
            {
                ViewData["message"] = Ex.Message;
                return View("Error");
            }
            return RedirectToAction("Index");
        }

        [Authorize]
        public ActionResult SearchProject(String Keyword, int PageIndex = 1)
        {
            Account LoginedAccount = Am.GetUserByUserName(User.Identity.Name);
            if (LoginedAccount.Role == "User")
            {
                ViewData["EditRight"] = false;
            }
            else
            {
                ViewData["EditRight"] = true;
            }
            PaginatedList<Project> Model = new PaginatedList<Project>(Pm.SearchProject(Keyword, User.Identity.Name), PageIndex, 10);
            if (PageIndex < 1 || PageIndex > Model.TotalPages)
            {
                ViewData["message"] = "Link is invalid, please try again";
                return View("Error");
            }

            ViewData["TempDelete"] = Pm.GetDeleteProjects();
            return View("Index", Model);
        }

        [Authorize]
        public ActionResult ViewDetails(String ProjectId)
        {
            Guid Pid;
            if (!Guid.TryParse(ProjectId, out Pid))
            {
                ViewData["message"] = "Project Id is invalid";
                return View("Error");
            }
            Project Model = Pm.GetProjectById(ProjectId);
            return View(Model);
        }

        [Authorize(Roles = "Group Admin,Project Admin")]
        public ActionResult Lookups(String ProjectId)
        {
            Guid G;
            if (!Guid.TryParse(ProjectId, out G))
            {
                ViewData["message"] = "Project Id is invalid";
                return View("Error");
            }
            LookupsModel Lm = Pm.GetLookups(ProjectId);
            return View(Lm);
        }

        [HttpPost]
        public ActionResult Lookups(FormCollection Forms)
        {
            String ReturnType = Forms["ReturnType"];
            String ProjectId = Forms["ProjectId"];

            LookupsModel Lm = Pm.GetLookups(ProjectId);

            if (ReturnType == "json")
            {
                List<Object> objects = new List<object>();

                objects.Add(new { Name = "Type", Items = Lm.DefectTypes });
                objects.Add(new { Name = "Status", Items = Lm.DefectStatuses });
                objects.Add(new { Name = "Version", Items = Lm.ProjectVersions });
                objects.Add(new { Name = "Priority", Items = Lm.DefectPriorities });

                return Json(objects);
            }

            return View(Lm);
        }

        [Authorize(Roles = "Group Admin,Project Admin")]
        public ActionResult GetAllLookups(String ProjectId)
        {
            Guid G;
            if (!Guid.TryParse(ProjectId, out G))
            {
                ViewData["message"] = "Project Id is invalid";
                return View("Error");
            }
            LookupsModel Lm = Pm.GetLookups(ProjectId);
            List<object> Obj = new List<object>();
            Pm.GetAllLookups("Type", Lm.DefectTypes, ref Obj);
            Pm.GetAllLookups("Status", Lm.DefectStatuses, ref Obj);
            Pm.GetAllLookups("Priority", Lm.DefectPriorities, ref Obj);
            Pm.GetAllLookups("Version", Lm.ProjectVersions, ref Obj);
            return Json(Obj, JsonRequestBehavior.AllowGet);
        }

        [Authorize(Roles = "Group Admin,Project Admin")]
        public ActionResult AddLookups(String ProjectId, string Type, string Value)
        {
            LookupType LT = LookupType.None;

            switch(Type)
            {
                case "Type": 
                    LT = LookupType.Type;
                    break;
                case "Version":
                    LT = LookupType.Version;
                    break;
                case "Status":
                    LT = LookupType.Status;
                    break;
                case "Priority":
                    LT = LookupType.Priority;
                    break;
                default:
                    break;
            }

            try
            {
                Pm.AddLookups(LT, Value, ProjectId);
                Object Obj = new { Success = "True" };
                return Json(Obj, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                Object Obj = new { Success = "False", Message = ex.Message };
                return Json(Obj, JsonRequestBehavior.AllowGet);
            }         
        }

        [Authorize(Roles = "Group Admin, Project Admin")]
        public ActionResult DeleteLookups(String ProjectId, string Type, string Value)
        {
            LookupType LT = LookupType.None;

            switch (Type)
            {
                case "Type":
                    LT = LookupType.Type;
                    break;
                case "Version":
                    LT = LookupType.Version;
                    break;
                case "Status":
                    LT = LookupType.Status;
                    break;
                case "Priority":
                    LT = LookupType.Priority;
                    break;
                default:
                    break;
            }

            try
            {
                Pm.DeleteLookups(LT, Value, ProjectId);
                Object Obj = new { Success = "True" };
                return Json(Obj, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                Object Obj = new { Success = "False", Message = ex.Message };
                return Json(Obj, JsonRequestBehavior.AllowGet);
            }         
        }

        [Authorize(Roles="Project Admin,Group Admin")]
        public ActionResult ChangeProjectMember(string ProjectId, int projectMemberPageIndex, int accountPageIndex, string keyWord)
        {
            Account account = Am.GetUserByUserName(User.Identity.Name);
            Project project = Pm.GetProjectById(ProjectId);

            if (account == null || !account.IsActive || account.Role == "User" || project.Account.GroupId != account.GroupId || account.Role == "System Admin")
            {
                ViewData["message"] = "Sorry, you don't permission to access this Project.";
                return View("Error");
            }
            else if (project == null)
            {
                ViewData["message"] = "Sorry, this project not existed or has been deleted.";
                return View("Error");
            }
            ProjectMemberModel memberModel;
            if (keyWord == "Search Member" || keyWord == "")
            {
                memberModel = new ProjectMemberModel(ProjectId, projectMemberPageIndex, accountPageIndex);
            }
            else
            {
                memberModel = new ProjectMemberModel(ProjectId, keyWord, projectMemberPageIndex, accountPageIndex);
            }
            return View(memberModel);
        }

        [Authorize(Roles = "Project Admin,Group Admin"), HttpPost]
        public ActionResult ChangeProjectMember(int projectMemberPageIndex, int accountPageIndex, string keyWord, FormCollection data)
        {
            try
            {
                Project project = Pm.GetProjectById(data["ProjectId"]);
                Account account = Am.GetUserByUserName(User.Identity.Name);
                if (!(account == null || !account.IsActive || account.Role == "User" || project.Account.GroupId != account.GroupId || account.Role == "System Admin"))
                {
                    string neededData = data["isAssigned"];
                    string projectId = data["ProjectId"];
                    char[] a = { ',' };
                    if (neededData == null)
                    {
                        neededData = " ";
                    }
                    string[] accountIds = neededData.Split(a);
                    List<ProjectMember> members = Pm.GetProjectMembers(projectId).ToList<ProjectMember>();
                    List<string> error = new List<string>();
                    foreach (ProjectMember member in members)
                    {
                        if (accountIds.Contains(member.AccountId.ToString()))
                        {
                            member.IsAssigned = true;
                        }
                        else
                        {
                            try
                            {
                                if (member.IsAssigned)
                                {
                                    member.IsAssigned = false;
                                    Pm.ToggleAssignForMember(member);
                                }
                            }
                            catch (Exception ex)
                            {
                                if (ex.Message == "You can't unassign this member to this project because this User has assigned to a (some) defect(s) of this project")
                                {
                                    error.Add(member.Account.UserName);
                                }
                            }
                        }
                    }
                    if (error.Count > 0)
                    {
                        string message = "Some account can't unassign because these account has assigned to defect: ";
                        for (int i = 0; i < error.Count - 1; i++)
                        {
                            message += error[i] + ", ";
                        }
                        message += error[error.Count - 1];
                        throw new Exception(message);
                    }

                    return RedirectToAction("ChangeProjectMember", new { projectMemberPageIndex = projectMemberPageIndex, accountPageIndex = accountPageIndex, keyWord = keyWord });
                }
                else
                {
                    throw new Exception("Sorry, you don't permission to do this action");
                }
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize(Roles = "Project Admin,Group Admin")]
        public ActionResult AddRemoveProjectMember(string AccountId, string ProjectId, int GroupMemberPageIndex, int ProjectMemberPageIndex, string Method, string KeyWord, string ReturnType, bool IsAssigned)
        {
            ProjectMember member;
            try
            {
                Guid accountId = Guid.Parse(AccountId);
                Guid projectId = Guid.Parse(ProjectId);
                Project project = Pm.GetProjectById(ProjectId);
                Account account = Am.GetUserByUserName(User.Identity.Name);
                if (!(account == null || !account.IsActive || account.Role == "User" || project.Account.GroupId != account.GroupId || account.Role == "System Admin"))
                {
                    if (Method.Equals("add", StringComparison.OrdinalIgnoreCase))
                    {
                        member = new ProjectMember();
                        member.ProjectId = projectId;
                        member.AccountId = accountId;
                        member.IsAssigned = false;
                        Pm.AddProjectMember(member);
                    }
                    else if (Method.Equals("remove", StringComparison.OrdinalIgnoreCase))
                    {
                        member = new ProjectMember();
                        member.ProjectId = projectId;
                        member.AccountId = accountId;
                        member.IsAssigned = false;
                        Pm.RemoveProjectMember(member);
                    }
                    else
                    {
                        member = new ProjectMember();
                        member.ProjectId = projectId;
                        member.AccountId = accountId;
                        member.IsAssigned = IsAssigned;
                        Pm.ToggleAssignForMember(member);
                    }
                    
                }
                ProjectMemberModel model;
                if (KeyWord == "Search Member" || KeyWord == "")
                    model = new ProjectMemberModel(ProjectId, ProjectMemberPageIndex, GroupMemberPageIndex);
                else model = new ProjectMemberModel(ProjectId, KeyWord, ProjectMemberPageIndex, GroupMemberPageIndex);
                if (ReturnType == "json")
                {
                    return Json(model);
                }
                else
                {
                    return View("ChangeProjectMember", model);
                }
            }
            catch (Exception ex) {
                if (ReturnType == "json")
                    return Json(ex.Message);
                else
                {
                    ViewData["message"] = ex.Message;
                    return View("Error");
                }
            }
            
        }

        [Authorize(Roles = "Project Admin, Group Admin"), HttpPost]
        public ActionResult SearchMember(string projectId, string keyWord)
        {
            ProjectMemberModel model;
            if (String.IsNullOrEmpty(keyWord) || keyWord == "Search Member")
                model = new ProjectMemberModel(projectId, 1, 1);
            else model = new ProjectMemberModel(projectId, keyWord, 1, 1);
            return Json(model);
        }

        [HttpPost, Authorize]
        public ActionResult Search(FormCollection Forms)
        {
            String Keyword = Forms["Keyword"];
            String ReturnType = Forms["ReturnType"];

            IQueryable<Project> Projects = Pm.SearchProject(Keyword, User.Identity.Name);

            if (ReturnType == "json")
            {
                List<Object> objects = new List<object>();

                foreach (Project p in Projects)
                {
                    objects.Add(new { Id = p.ProjectId, Name = p.ProjectName });
                }

                return Json(objects);
            }
            else
            {
                return View();
            }
        }

        [HttpPost, Authorize]
        public ActionResult SearchAssignedMember(FormCollection Forms)
        {
            String Keyword = Forms["Keyword"];
            String ReturnType = Forms["ReturnType"];
            String ProjectId = Forms["ProjectId"];

            var Accounts = Pm.SearchAssignedMember(ProjectId, Keyword);

            if (ReturnType == "json")
            {
                List<Object> objects = new List<object>();

                foreach (Account a in Accounts.ToList())
                {
                    Profile p = a.Profiles.FirstOrDefault();
                    objects.Add(
                        new { 
                            Id = a.AccountId, 
                            FirstName = p.FirstName, 
                            LastName = p.LastName,
                            Email = p.Email
                        });
                }

                return Json(objects);
            }
            else
            {
                return View();
            }
        }

        [HttpPost, Authorize]
        public ActionResult AutoCompleteProjectMember(FormCollection Forms)
        {
            String Keyword = Forms["Keyword"];
            String DefectId = Forms["DefectId"];

            Defect defect = Dm.GetDefect(DefectId);

            var Accounts = Pm.SearchProjectMember(defect.ProjectId.ToString(), Keyword);

            List<Object> objects = new List<object>();

            foreach (Account a in Accounts.ToList())
            {
                Profile p = a.Profiles.FirstOrDefault();
                objects.Add(
                    new
                    {
                        Id = a.AccountId,
                        FirstName = p.FirstName,
                        LastName = p.LastName,
                        Email = p.Email
                    });
            }

            return Json(objects);
        }
    }
}